当浏览器加载页面时,它会“读取”(或者称之为:“解析”)HTML 并从中生成 DOM 对象。对于元素节点,大多数标准的 HTML 特性(attributes)会自动变成 DOM 对象的属性(properties)

但特性与属性映射并不是一一对应的!

attribute

attribute 自动映射为 property

浏览器解析 HTML 文本,并根据标签创建 DOM 对象,会辨别标准的特性(attribute)并以此创建 DOM 属性(properties),但是非标准的特性则不会:

<body id="test" something="non-standard">
  <script>
    // 标准特性会添加到 DOM 属性
    console.log(document.body.id) // test
    // 非标准的特性不会
    console.log(document.body.something); // undefined
  </script>
</body>

注意:

操作 attribute

可以使用 elem.attributes 读取所有 attribute,属于内建 Attr 类的对象的集合,具有 name 和 value 属性:

for (let attr of elem.attributes) {
  console.log(attr.name, attr.value)
}

所有 attribute 都可以通过使用以下方法进行访问:

其中,key 和 value 都是字符串类型(因为其操作的实际上是 HTML 中的内容),不是字符串的话会进行 [[002.数据类型#隐式类型转换|隐式类型转换]]

即:

同时还有相应的 elem.*AttributeNS() 方法,用于 [[002.DOM:节点与集合#命名空间|命名空间]]。

attribute、property 同步

当一个标准的 attribute 被改变,对应的 property 也会自动更新(除了几个特例),反之亦然。

<input>

<script>
  let input = document.querySelector('input');

  // 特性 => 属性
  input.setAttribute('id', 'id');
  alert(input.id); // id(被更新了)

  // 属性 => 特性
  input.id = 'newId';
  alert(input.getAttribute('id')); // newId(被更新了)
</script>

例外,例如 input.value 只能从 attribute 同步到 property,反过来则不行:

<input>

<script>
  let input = document.querySelector('input');

  // 特性 => 属性
  input.setAttribute('value', 'text');
  alert(input.value); // text

  // 这个操作无效,属性 => 特性
  input.value = 'newValue';
  alert(input.getAttribute('value')); // text(没有被更新!)
</script>

property

DOM 节点是 JS 对象

DOM 节点是常规的 JS 对象,可以向普通 JS 对象一样操作:

// 添加属性
document.body.myData = {
  name: 'Caesar',
  title: 'Imperator'
}
console.log(document.body.myData.title) // 'Imperator'

// 添加方法
document.body.sayTagName = function() {
  alert(this.tagName)
}
document.body.sayTagName() // BODY

// 修改原型
Element.prototype.sayHi = function() {
  alert(`Hello, I'm ${this.tagName}`)
}
document.documentElement.sayHi() // Hello, I'm HTML
document.body.sayHi() // Hello, I'm BODY

// ...

property 不同与 attribute

property 不总是字符串类型。例如,input.checked 属性(type="checkbox")是布尔型:

<input id="input" type="checkbox" checked>checkbox</input>

<script>
  console.log(input.getAttribute('checked')) // ""
  console.log(input.checked) // true
</script>

还有其他的例子:style 属性是一个对象:

<div id="div" style="color:red;font-size:120%">Hello</div>

<script>
  // 字符串
  console.log(div.getAttribute('style')) // "color:red;font-size:120%"

  // 对象
  console.log(div.style) // [object CSSStyleDeclaration]
  console.log(div.style.color) // "red"
</script>

还有 property 是字符串类型,但它和 attribute 不同。例如,href property 一直是一个完整的 URL:

<a id="a" href="#hello">link</a>

<script>
  console.log(a.getAttribute('href')) // "#hello"

  console.log(a.href) // "http://localhost:8080/page#hello"
</script>

自定义属性:data-*

所有以 “data-” 开头的 attribute 均被保留供程序员使用。它们可在 dataset property 中使用:

<div id="order" data-order-state="123">A new order.</div>

<script>
  // 读取
  console.log(order.dataset.orderState) // "123"

  // 修改
  order.dataset.orderState = "pending"
</script>

使用 data-* 特性是一种合法且安全的传递自定义数据的方式。

注意: